#include "MyMatrix.h"
#include <iostream>

// construct a new matrix with a size
MyMatrix::MyMatrix(int width, int height):
	_width(width),
	_height(height)
{
	_matrix = new double[width * height];
	Clear();
}

	// copy constructor used to copy array data over
MyMatrix::MyMatrix(MyMatrix& copy)
{
	this->_height = copy._height;
	this->_width = copy._width;

	_matrix = new double[_width * _height];
	for(int i = 0; i < (_width*_height); i++)
	{
		_matrix[i] = copy._matrix[i];
	}
}

const double* MyMatrix::GetRoto()
{
	return _matrix;
}

/// delete stuff
MyMatrix::~MyMatrix(void)
{
	delete [] _matrix;
}
// emptys the matrix
void MyMatrix::Clear()
{
	for(int i = 0; i <(_width*+_height); i++)
	{
		// set everything to zero for safety
		_matrix[i] = 0;
	}
}
// returns the location in the matrix
double& MyMatrix::at(int x, int y)
{
	if(x < _width && y < _height)
	{
		int pos = y  + (x * _width);
		return _matrix[pos];
	}
	else
	{
		throw "Out of bounds error";
	}
}

// this is just a print incase i need 
void MyMatrix::ToString()
{
	for(int i = 0; i < _height; i++)
	{
		for(int j = 0; j < _width; j++)
		{
			std::cout << "|" << this->at(j,i) << "|";
		}
		std::cout << std::endl;
	}
	
}

MyMatrix MyMatrix::Transpose()
{
	MyMatrix tran(_height, _width);
	for(int i = 0; i < _height; i++)
	{
		for(int j = 0; j < _width; j++)
		{
			tran.at(i,j) = this->at(j,i);
		}
	}

	return tran;
}

// propery copys over the array that represents the matrix
MyMatrix MyMatrix::operator= (const MyMatrix& value)
{
	if(value._width == this->_width && value._height == this->_height)
	{
		_width = value._width;
		_height = value._height;
		for(int i = 0; i < (_width*_height); i++)
		{
			_matrix[i] = value._matrix[i];
		}
		return *this;
	}
	throw "Out of bounds error";
}

// matrix addtion
MyMatrix MyMatrix::operator+ (MyMatrix value)
{
	if(value._width == this->_width && value._height == this->_height)
	{
		// run through the array for addition
		MyMatrix result(this->_width, this->_height);
		for(int i = 0; i < (_width*_height); i++)
		{
			// run through each and add
			result._matrix[i] = this->_matrix[i] + value._matrix[i];
		}

		return result;
	}
	throw "Out of bounds error";

}

// matrix 
MyMatrix MyMatrix::operator- (MyMatrix value)
{
	if(value._width == this->_width && value._height == this->_height)
	{
		// run through the array for subtraction
		MyMatrix result(this->_width, this->_height);
		for(int i = 0; i < (_width*_height); i++)
		{
			result._matrix[i] = this->_matrix[i] - value._matrix[i];
		}

		return result;
	}
	throw "Out of bounds error";

}

// // matrix multiplication
MyMatrix MyMatrix::operator* (MyMatrix value)
{
	if(this->_width == value._height)
	{
		MyMatrix result(value._width, this->_height);
		// start the multiplication
		for(int i = 0; i < value._width; i++)
		{
			for(int j = 0; j < this->_height; j++)/// each point
			{
				// add up all the points for the rows
				for(int k = 0; k < this->_width; k++)
				{
					result.at(i,j) +=  this->at(k,j) * value.at(i,k); 
				}
			}
		}
		return result;
	}
	throw "Out of bounds error";
}

// extras just to make it easyer
MyMatrix MyMatrix::operator+=(MyMatrix value)
{
	*this = *this + value;
	return *this;
}

MyMatrix MyMatrix::operator-=(MyMatrix value)
{
	*this = *this - value;
	return *this;
}

MyMatrix MyMatrix::operator*=(MyMatrix value)
{
	*this = *this * value;
	return *this;
}